package com.gaofei.loans.controller;

import com.bw.itext.pdf.service.PdfService;
import com.bw.springboot.starter.upload.model.Chunk;
import com.bw.springboot.starter.upload.service.FileService;
import com.bw.springboot.starter.upload.util.FileResult;
import com.gaofei.loans.domain.ActivitiVo;
import com.gaofei.loans.domain.Loans;
import com.gaofei.loans.domain.UserTask;
import com.gaofei.loans.service.LoansService;
import io.jsonwebtoken.impl.crypto.MacProvider;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@RestController
@RequestMapping("loans")
@Slf4j
public class LoansController {

    @Resource
    LoansService loansService;


    @Resource
    RuntimeService runtimeService;


    @Resource
    TaskService taskService;

    @Resource
    HistoryService historyService;

    @Resource
    RepositoryService repositoryService;

    @Autowired
    private FileService fileService;

    @Autowired
    PdfService pdfService;


    //生成后的pdf预览接口
    @RequestMapping("preview")
    public String preview(HttpServletResponse resp) throws IOException {
//        预览pdf
        pdfService.preview("loans.sign.pdf",resp);

        return "success!!!";
    }
    /**
     * 电子签章
     * @return
     * @throws IOException
     */
    @RequestMapping("pdf")
    public String pdf1() throws IOException {
        List<Loans> list = new ArrayList<>();//模拟从数据查询的已审核的数据
        Loans loans1 = new Loans(1, "张大", 250000.0, 30, null, null, 1 + "");//模拟从数据库查询的数据
        Loans loans2 = new Loans(2, "zhangsan", 300000.0, 10, null, null, 1 + "");//模拟从数据库查询的数据
        Loans loans3 = new Loans(3, "gaofei", 100000.0, 30, null, "http://localhost:9988/71231518-1eurekawmv/1.eureka高可用搭建.wmv", 1 + "");//模拟从数据库查询的数据
        list.add(loans1);
        list.add(loans2);
        list.add(loans3);
//        生成pdf
        pdfService.export(list, "loans.pdf", "导出demo", Loans.class);
//        电子签章
        pdfService.sign("loans.pdf", "loans.sign.pdf");

        return "success!!!";
    }
    /**
     * 文件分块上传
     * @param chunk
     * @return
     * @throws InterruptedException
     */
    @RequestMapping("postFileUpload")
    public Object postFileUpload(@ModelAttribute Chunk chunk) throws InterruptedException {
        fileService.postFileUpload(chunk);
        if (chunk.getTotalChunks().equals(chunk.getChunkNumber())) {
            TimeUnit.SECONDS.sleep(2);
            FileResult fileResult = fileService.mergeFile(chunk);
            return fileResult;
        }
        log.info("文件上传成功");
        return "success!";
    }
    /**
     * 提交审批,开启流程的接口
     * @return
     */
    @RequestMapping("ask4Biz")
    public String ask4Biz( @RequestBody Loans loans){

        if(loans==null){
            throw new RuntimeException("参数不能为空!");
        }
        //1.接收前台传过来的贷款信息

        //2.将信息保存到数据库的业务表中

        loansService.save(loans);
        //3.保存的数据返回来的主键id,作为业务key,在开启流程实例的时候,传递进去
        String businessKey= loans.getId()+"";
        //3.1 开启流程实例,传入业务key
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("loans", businessKey);
        String processInstanceId = processInstance.getProcessInstanceId();
        //4.把流程实例id更新的数据库
        //TODO
        return "提交审批成功";
    }

    //查询任务待办接口
    @RequestMapping("queryUserTaskByUserName")
    public Object findTaskByProcessId(@RequestBody ActivitiVo activitiVo){


        List<Task> loans = taskService.createTaskQuery()
                //根据登录用户名查询
                .taskAssignee(activitiVo.getUsername())
                .processDefinitionKey("loans")
                .list();
        ArrayList<UserTask> userTasks = new ArrayList<>();

        for (Task task : loans) {
            //根据任务ID获取当前流程实例
            Map<String, Object> taskMap = new HashMap<>();
            taskMap.put("id", task.getId());
            taskMap.put("name", task.getName());
            taskMap.put("assignee", task.getAssignee());
            taskMap.put("description", task.getDescription());
            taskMap.put("processInstanceId", task.getProcessInstanceId());
            taskMap.put("parentTaskId", task.getParentTaskId());
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).singleResult();
            String businessKey = historicProcessInstance.getBusinessKey();
//            //businessKey就是业务表的主键
//            //根据这个主键查询业务表的数据封装到map
            Loans l = loansService.findLoansById(businessKey);
//            //把leave中的数据封装进taskMap,返回给前端

            UserTask userTask = new UserTask(l,taskMap, historicProcessInstance);
            userTasks.add(userTask);

        }
        return userTasks;
    }

    @Resource
    private KafkaTemplate<String,String> kafkaTemplate;

    //kafka  总经理审批就必须发送kafka消息
    //审核
    @RequestMapping("completeUserTaskById")
    public Object completeUserTaskById(@RequestBody ActivitiVo activitiVo) {
        HashMap<String, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("money", activitiVo.getMoney());//流程变量
        taskService.complete(activitiVo.getTaskId(), objectObjectHashMap);//完成任务

        //对流程实例做查询
        //如果null说明结束否则就是待审批
        ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(activitiVo.getProcessInstanceId()).singleResult();
        if(process==null){
            //更新业务表审核状态为0结束

        }else{
            //更新业务表待审批  0 待审批
        }

        if(activitiVo.getTaskName().equals("银行总经理审批")){
            String s = UUID.randomUUID().toString();
            //往kafka发送消息
            ListenableFuture<SendResult<String, String>> send = kafkaTemplate.send("yuekao", s, "pass");
            send.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
                @Override
                public void onFailure(Throwable throwable) {
                    //消息发送失败,会执行这个函数
                    //可以发送相关提醒给开发人员,重试
                }

                @Override
                public void onSuccess(SendResult<String, String> stringStringSendResult) {
                    //消息发送成功会执行这个函数
                    System.out.println("生产者已经成功发送消息到broker了");
                }
            });
        }



        return "success";
    }

    //查看流程图,进度追踪
    @RequestMapping(value = "/image")
    public void lookImg(String processInstanceId, HttpServletResponse response) throws IOException, TranscoderException {
        InputStream in = this.getProcessDiagram(processInstanceId);

        //svg 转  png
        byte[] streamBytes = IOUtils.toByteArray(in);
        ByteArrayOutputStream byteArrayOutputStream = svgToPng(streamBytes);
        String imageName = "image" + Instant.now().getEpochSecond() + ".png";
//        byteArrayOutputStream.writeTo(new FileOutputStream(new File("D:/images/"+imageName)));
//        FileInputStream fis = new FileInputStream(new File("D:/images/" + imageName));
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

        response.setContentType("text/html; charset=UTF-8");
        response.setContentType("image/png");
        response.addHeader("Content-Disposition", "inline; filename=" + imageName);
        ServletOutputStream outputStream = response.getOutputStream();
        IOUtils.copy(byteArrayInputStream, outputStream);
        outputStream.close();
    }

    //svg 转  png
    private ByteArrayOutputStream svgToPng(byte[] streamBytes) throws TranscoderException, IOException {

        PNGTranscoder t = new PNGTranscoder();

        TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(streamBytes));

        ByteArrayOutputStream ostream = new ByteArrayOutputStream();

        TranscoderOutput output = new TranscoderOutput(ostream);

        t.transcode(input, output);

        ostream.flush();
        return ostream;

    }


    /**
     * Get Process instance diagram
     */
    public InputStream getProcessDiagram(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();

        List<String> highLightedActivities = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list().stream().map(item -> item.getActivityId()).collect(Collectors.toList());

        // null check
        if (processInstance != null) {
            // get process model
            BpmnModel model = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            if (model != null && model.getLocationMap().size() > 0) {
                ProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
                // 生成流程图 已启动的task 高亮
                return generator.generateDiagram(model,
                        runtimeService.getActiveActivityIds(processInstanceId), highLightedActivities, "simsun", "simsun", "simsun");
                // 生成流程图 都不高亮
//                return generator.generateDiagram(model,Collections.<String>emptyList());
            }
        }
        return null;
    }

}
